Spring 笔记之装配

概述

​ 这几天断断续续的在看Spring实战,主要看了前两章的东西,特此记录一下。

依赖注入

​ 作为Spring最为核心的概念,依赖注入(Dependency Injection,DI)这个名词既绕口,也没那么好理解。他其实是一种软件工程设计原则控制反转(Inversion of Control,IoC)的一种实现。

究其目的,是为了能够减少面向对象软件工程中多对象之间耦合度太高的问题。具体到Spring框架来说,在Spring的世界观里面,对象之间的创建与调用都应该由Spring的IoC容器来负责,而不应该由对象之间相互调用,这种设计思想,可以能够很好的减少对象之间的相互耦合。而在Spring中如何自动的创建对象实例bean呢,这种行为在Spring中的名词就是装配(Wiring)。随着框架的完善,今天的Spring主要以三种方式来完成对Java Bean的装配。

装配方式

自动装配

​ Spring发展到如今,自动化的程度很高,自动装配也是非常方便并且在Spring Boot框架中大量使用。在Spring实战这本书中,也属于重点介绍的技术,Spring技术主要通过两个角度来实现自动化的装配:

  • 组件扫描(component scanning):Spring自动发现应用上下文中(ApplicationContext)所创建的bean
  • 自动装配(autowiring): Spring自动的满足bean之间的相互依赖

​ 举个例子可以很清楚的看见Spring是如何通过自动装配的方式来完成自动的装配。假设以Spring Boot框架为例,有一个Singer去演唱一首歌,那么当他需要唱歌时需要哪些东西呢,在Spring的自动装配中,比较简单。首先需要定义能够唱歌的灵魂歌手LeiJun:

1
2
3
4
5
6
7
@Component
public class LeiJun implements Singer {
@Override
public void sing() {
System.out.println("Are you ok?");
}
}

光有人是不够的,如何能够唱歌呢,注入进来就好了!

1
2
3
4
5
6
7
8
9
10
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = DemoApplication.class)
public class DemoApplicationTests {
@Autowired
private LeiJun leiJun;
@Test
public void test(){
leiJun.sing();
}
}

在Spring中,利用自动装配去使用一个对象就这么简单,依靠@Component注解与@Autowired注解就能够完成对一个对象的使用,但其实在这背后,Spring默默的为我们做了很多的事情。首先,当为一个对象定义为@Component注解时,相当于对Spring声明了这个类将会作为组件类,并且告知Spring要为这个类创建bean,当然,组件的扫描并不是直接启动的,需要通过对Spring的配置从而启动对所有@Component的注解的扫描,并创建相应的bean,以Spring Boot为例,在其启动时会有一个@SpringBootApplication注解,这其实是个多重注解的组合,

1
2
3
4
5
6
7
8
9
10
11
12
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

其中,ComponentScan的作用尤为重要,在项目启动的时候,该注解会去扫描根据配置好的Package下的类,在本例中,他就会将加载了@Component注解的LeiJun加载入Ioc容器中并自动为其创建一个bean,而如单元测试中例子所示,当在Spring框架中需要引用一个bean时,通过@Autowired将其从IoC容器中注入进来就可以使用了。

​ 以上,就是通过自动装配的姿势,让LeiJun唱歌的过程。

JavaConfig装配

并不是任何时候自动配置都是合适的场景,这种时候 ,总需要去执行Plan B,此时,可能就需要我们对JavaBean进行的显示的配置了,JavaConfig的装配方式比较特殊,因为他就是Java代码,就像程序中的其他代码一样,只不过不包含任何业务逻辑,显得比较独立。再以一位歌手为例,就能清楚JavaConfig的配置方式。首先,都需要定义一位歌手:

1
2
3
4
5
6
public class GongLinNa implements Singer{
@Override
public void sing() {
System.out.println("法海你不懂爱");
}
}

相比较上次而言,这位歌手并没有一个Component注解,这是因为她没有选择通过自动装配的方式注入进IoC容器的缘故,通过JavaConfig,可以达到同样的目的!

1
2
3
4
5
6
7
@Configuration
public class SingerConfig {
@Bean
public Singer gongLinNa(){
return new GongLinNa();
}
}

同样也可以唱歌:

1
2
3
4
5
6
7
8
9
10
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = DemoApplication.class)
public class DemoApplicationTests {
@Autowired
private Singer gongLinNa;
@Test
public void test002(){
gongLinNa.sing();
}
}

如方式一相比,能够明显的观察出不同,少了一个@Component注解,多了一个SingerConifg类。这个类中,多了两个注解@Configuration@Bean。其实从名字就能够看出,Configuration表明应用了这个注解的Java类就是一个Java配置类,而@Bean则表明了这个方法将为Spring返回一个Bean,通过这种方式,Spring同样能够将其注入进来,并在其他的地方注入使用。相比较与自动注入而言,这种要稍微繁琐一点。使用场景,以Spring Boot为例,Spring Boot 各种起步starter中的很多基础包都是以这种方式配置,并且通过EnableAutoConfiguration将符合条件的配置加载到容器中来并且使用。

XML方式

xml方式的配置方式,在Spring中,有着悠久的历史。简而言之,类似与JavaConfig方式,只不过这种bean的方式并不是通过Java代码,而是xml的方式进行约定。由于其历史的悠久性,注定了其繁琐程度也要大大高于另外两种方式,在如今的项目工程中,实际使用的也并不多。通常情况下,自动装配和JavaConfig就已经足够使用了。

常用注解

Spring并不会通过强制约定项目代码去实现一个Spring规范的接口或者集成Spring规范的类,通常来说,当需要使用起Spring的特性,注解是必不可少的,在进行依赖注入的使用过程中,以下的几个注解是我能够经常看到的。

@Component: 这个简单的注解通常注解在类上,表明这个类是Spring的一个组件,而Spring看到这样的类,当配置了自动扫描时,将会自动将其收集到容器中并为其创建bean。

@Service @Controller @Repository : 虽然Component注解非常好用,但在实际的应用过程中,这三个注解其实是更常用的。以@Service为例:

1
2
3
4
5
6
7
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
String value() default "";
}

可以发现,它上面也有一个@Component注解,为什么要使用他们而不是直接使用@Component呢,其实只是为了表意更清楚而已,Service表明这是一个Service层的对象,Controller表明这是一个控制层组件,而Repository则表明这是一个与数据访问相关的组件。

@ComponentScan: 自动扫描注解,这个注解通常配置在Spring应用启动时,当启动应用时,ComponentScan注解就可以去搜集所有已经声明了的组件并将它们组装入容器中。

@Autowired: 当Bean已经在容器时,一个Atuowired即可注入到当前类中并进行使用.

@Configuration: 标注在类上,表明这是一个JavaConfiguration类.

@Bean 标注于方法上面,表面将返回一个JavaBean.